#import "MapView.h"
#define TILE_SIZE 1024

inline void NSRectScale( NSRect * rect, float scale_factor ) {
	rect->origin.x = rect->origin.x * scale_factor;
	rect->origin.y = rect->origin.y * scale_factor;
	rect->size.width = rect->size.width * scale_factor;
	rect->size.height = rect->size.height * scale_factor;
}

@implementation MapView

static int coffset = 0;

static NSArray * colors;
static NSColor * LocationColor = NULL;
static NSColor * LocationBorderColor = NULL;

- (id)initWithFrame:(NSRect)frameRect
{
	if ((self = [super initWithFrame:frameRect]) != nil) {
		// Add initialization code here	
		selectedX = 0;
		selectedY = 0;
		_loadingCachedImage = YES;
		[[self window] makeFirstResponder:self];
		colors = [NSArray arrayWithObjects:[NSColor redColor], [NSColor blueColor], [NSColor greenColor], [NSColor yellowColor], [NSColor orangeColor], [NSColor purpleColor], NULL];
		[colors retain];
		_scaleFactor = 1.0;
		_selectedUnits = [[NSMutableSet alloc] init];
		[NSTimer scheduledTimerWithTimeInterval:1.0/15.0 target:self selector:@selector(timerFired:) userInfo:NULL repeats:YES];
		_mode = MAP_MODE_SELECTION;
	}
	return self;
}

- (void)timerFired:(NSTimer *)aTimer {
	[self setNeedsDisplay:YES];
}

- (void)setTileMap:(TileMap *)map
{
	if( map != _map ) {
		[_map release];
		_map = [map retain];
		[self setFrameSize:NSMakeSize( [_map width] * 32 / _scaleFactor , [_map height] * 32 / _scaleFactor )];
	}
}

- (void)setTilePieceList:(TilePieceList *)pieceList {
	if( pieceList != _pieceList ) {
		[_pieceList release];
		_pieceList = [pieceList retain];
	}
}


- (void)setTileGroupList:(TileGroupList *)groupList {
	if( groupList != _groupList ) {
		[_groupList release];
		_groupList = [groupList retain];
	}
}

- (void)setTileList:(TileList *)tileList {
	if( tileList != _tileList ) {
		[_tileList release];
		_tileList = [tileList retain];
	}
}

- (void)setPalette:(ColorPalette *)palette {
	if( palette != _palette ) {
		[_palette release];
		_palette = [palette retain];
	}
}

- (void)setUnitList:(UnitList *)unitList {
	if( unitList != _unitList ) {
		[_unitList release];
		_unitList = [unitList retain];
	}
}

- (void)setLocationList:(LocationList *)locationList {
	if( _locationList != locationList ) {
		[_locationList release];
		_locationList = [locationList retain];
	}
}
static int muta = 0;

- (void)drawRect:(NSRect)rect
{
	if( _palette == NULL ||
		_tileList == NULL ||
		_pieceList == NULL ||
		_groupList == NULL ||
		_map == NULL ) {
			return;
		}
	  
	if( _loadingCachedImage == YES ) {
		[self buildCachedImage:NULL];
	}
	
	muta++;
	if( muta > 39 ) {
		muta  =0 ;
	}
	int minX = (rect.origin.x / TILE_SIZE) / _scaleFactor;
	int maxX = (rect.origin.x + rect.size.width) / TILE_SIZE * _scaleFactor;
	
	if( maxX < numWide ) {
		maxX++;
	}
	
	int minY = (rect.origin.y / TILE_SIZE) / _scaleFactor;
	int maxY = (rect.origin.y + rect.size.height) / TILE_SIZE * _scaleFactor;
	
	if( maxY < numHigh ) {
		maxY++;
	}
	
	int X, Y;
	for( X = minX; X < maxX; X++ ) {
		for( Y = minY; Y < maxY; Y++ ) {
			NSRect inRect = NSMakeRect( X * TILE_SIZE / _scaleFactor , Y * TILE_SIZE / _scaleFactor, TILE_SIZE / _scaleFactor, TILE_SIZE / _scaleFactor );//rect;
			NSRect fromRect = NSMakeRect( 0,0, TILE_SIZE , TILE_SIZE );
			[[_cachedBackgroundViews objectAtIndex: Y  * numWide + X] drawInRect:inRect fromRect:fromRect operation:NSCompositeCopy fraction:1.0];
		}
	}
	
	if( LocationColor == NULL ) {
		LocationColor = [[NSColor colorWithCalibratedRed:0.0 green:0.2 blue:0.5 alpha:0.2] retain];
	}
	
	if( LocationBorderColor == NULL ) {
		LocationBorderColor = [[NSColor colorWithCalibratedRed:0.0 green:0.2 blue:0.5 alpha:0.5] retain];
	}
	
	int unitIndex;
	for( unitIndex = 0; unitIndex < [_unitList unitCount]; unitIndex++ ) {
		Unit * unit = [_unitList unitAtIndex: unitIndex];
		//NSLog(@"%i = unit->type ", [unit type] );
		Sprite * sprite = [[DATManager sharedManager] spriteForUnitIdentifier:[unit type]];
		[self drawSprite:sprite forUnit:unit];
		
		if( [unitEditController containsUnit: unit ] ) {
			NSRect selectionRect = [self boundingRectangleForUnit:unit sprite:sprite];
			NSLog(@"%i - %@", unitIndex, NSStringFromRect( selectionRect ));
			NSBezierPath * selectionPath = [NSBezierPath bezierPathWithOvalInRect:selectionRect];
			[[NSColor greenColor] set];
			[selectionPath stroke];
		}
		NSRect drawRect = [self boundingRectangleForUnit:unit sprite:sprite];
		NSAttributedString * string = [[NSAttributedString alloc] initWithString:NSStringFromRect( drawRect ) attributes:[NSDictionary dictionaryWithObjectsAndKeys:[NSFont systemFontOfSize:10.0f], NSFontAttributeName, [NSColor whiteColor], NSForegroundColorAttributeName, NULL]];
		[string drawAtPoint:drawRect.origin];
	}
	
	int locationIndex;
	for( locationIndex = 0; locationIndex < [_locationList locationCount]; locationIndex++ ) {
		NSRect locationRect = [_locationList rectForLocationAtIndex: locationIndex ];
		locationRect.origin.y = [_map height] * 32 - locationRect.origin.y;
		NSBezierPath * locationPath = [NSBezierPath bezierPathWithRect: locationRect ];
		[LocationColor set];
		[locationPath fill];
		[LocationBorderColor set];
		[locationPath stroke];
		
		NSAttributedString * locationNameString = [[NSAttributedString alloc] initWithString:[_locationList nameForLocationAtIndex: locationIndex ] attributes:[NSDictionary dictionaryWithObjectsAndKeys:[NSColor redColor], NSForegroundColorAttributeName, NULL]];
		NSRect stringBounds = [locationNameString boundingRectWithSize:NSMakeSize(32,32) options:NSStringDrawingOneShot];
		[locationNameString drawAtPoint:NSMakePoint( NSMinX( locationRect ), NSMaxY( locationRect ) - stringBounds.size.height)];
		[locationNameString release];
	}

	[miniMapView setNeedsDisplay:YES];
}

- (void)drawSprite:(Sprite *)sprite forUnit:(Unit *)unit {
	int frame = [unit frameNumber];
	
	if( frame != 0 ) {
		//NSLog(@"Drawing Frame %i", frame );
	}
	
	NSImage * img = [[NSImage alloc] init];
	[img addRepresentation: [ sprite frameAtIndex:frame owner: [unit owner] +coffset ]];
	NSRect fromRect = NSMakeRect(0,0,[sprite boundingWidth], [sprite boundingHeight]);
	NSRect inRect = [self boundingRectangleForUnit:unit sprite:sprite];
	[[NSColor blueColor] set];
	[[NSBezierPath bezierPathWithRect:inRect] stroke];
	
//	inRect.origin.x -= [sprite horizOffsetForFrame:frame];
//	inRect.origin.y += [sprite verticalOffsetForFrame:frame];
	
	frame++;
	if( frame >= [sprite frameCount]-1 ) {
		frame = 0;
	}
	//NSLog(@"%i vs. %i", frame, [sprite frameCount]);
	[unit setFrameNumber:frame];
	//NSLog(@"Set to %i",  [unit frameNumber]);
	
//	inRect.origin.y += [sprite verticalOffsetForFrame:0];
	
	[img drawInRect:inRect fromRect:fromRect operation:NSCompositeSourceOver fraction:1.0];
	[img release];
}

- (void)buildCachedImage:(id)context {
	numWide =  [_map width] * 32 / TILE_SIZE;
	numHigh =  [_map height] * 32 / TILE_SIZE;
	NSLog(@"Image will be %ix%i tiles", numWide, numHigh);
	_cachedBackgroundViews = [[NSMutableArray alloc] init];
	
	int i,j;
	for( j = 0; j < numHigh; j++ ) {
		for( i = 0; i < numWide; i++ ) {
			NSImage * tile = [[NSImage alloc] initWithSize:NSMakeSize(TILE_SIZE,TILE_SIZE)];
			[_cachedBackgroundViews addObject:tile];
			[tile release];
			[[_cachedBackgroundViews objectAtIndex:numWide * j + i] lockFocus];
			
			int numSubTilesInTile = TILE_SIZE / 32;
			
			int X = i * numSubTilesInTile;
			int Y = j * numSubTilesInTile;
			int XM = (i+1) * numSubTilesInTile;
			int YM = (j+1) * numSubTilesInTile;
			for(X = i * numSubTilesInTile ; X < XM ; X++ ) {
				for( Y = j * numSubTilesInTile; Y < YM; Y++ ) {
					u_int16_t mapTileID = [_map tileAtX:X Y:Y];
					int tileIndex = [_groupList indexForGroup:(mapTileID / 16) member:(mapTileID % 16)];
					
					NSImage * image = [_tileList bitmapForTileAtIndex: tileIndex];
					NSPoint pointToDraw = NSMakePoint( (X * 32) % TILE_SIZE , (Y * 32) % TILE_SIZE );
					[image drawAtPoint:pointToDraw fromRect:NSMakeRect(0,0,32,32) operation:NSCompositeCopy fraction:1.0];
				}
			}
			
			[[_cachedBackgroundViews objectAtIndex:numWide * j + i] unlockFocus];
		}
	}
	_loadingCachedImage = NO;
}

- (BOOL)acceptsFirstResponder {
	return YES;
}

- (BOOL)becomeFirstResponder {
	return YES;
}

- (BOOL)resignFirstResponder {
	return NO;
}

- (IBAction)changeScaleFactor:(id)sender {
	[self setScaleFactor:(float)[[sender selectedItem] tag]];
}

- (void)setScaleFactor:(float)scale {
	_scaleFactor = scale;
	[self setFrameSize:NSMakeSize( [_map width] * 32 / _scaleFactor , [_map height] * 32 / _scaleFactor )];
	[self setNeedsDisplay:YES];
}

- (float)scaleFactor {
	return _scaleFactor;
}

- (void)keyDown:(NSEvent *)theEvent {
	NSString * theKey = [theEvent characters];
	
	unichar c = [theKey characterAtIndex:0];
	switch( c ) {
		case NSLeftArrowFunctionKey:
			selectedX = selectedX > 0 ? selectedX - 1 : selectedX;
			[self setNeedsDisplay:YES];
			break;
		case NSRightArrowFunctionKey:
			selectedX = selectedX < [_map width] - 1 ? selectedX + 1 : selectedX;
			[self setNeedsDisplay:YES];
			break;
		case NSUpArrowFunctionKey:
			selectedY = selectedY < [_map height] - 1 ? selectedY + 1 : selectedY;
			[self setNeedsDisplay:YES];
			break;
		case NSDownArrowFunctionKey:
			selectedY = selectedY > 0 ? selectedY - 1 : selectedY;
			[self setNeedsDisplay:YES];
			break;
		case 'c': {
			coffset++;
			if( coffset > 11 ) {
				coffset = 0;
			}
			[self setNeedsDisplay:YES];
			break;
		}
	}
}

- (NSString *)coordinateValue {
	return [NSString stringWithFormat:@"(%i, %i)", selectedX, selectedY];
}

- (void)mouseDown:(NSEvent *)theEvent {
//	NSLog( @"[theEvent locationInWindow] = %@", NSStringFromPoint( [theEvent locationInWindow] ) );
	NSScrollView * sv = (NSScrollView *)[self superview];
	NSPoint transformedPoint = NSMakePoint( [theEvent locationInWindow].x - [sv frame].origin.x +  [sv documentVisibleRect].origin.x, ([theEvent locationInWindow].y - [sv frame].origin.y - ([NSScroller scrollerWidth]) + [sv documentVisibleRect].origin.y) );
//	NSLog( @"transformed point = %@",  NSStringFromPoint( transformedPoint ));

	int unitIndex;	

	BOOL selectedSomething = NO;
	switch( _mode ) {
		case MAP_MODE_SELECTION:
			for( unitIndex = 0; unitIndex < [_unitList unitCount]; unitIndex++ ) {
				Unit * unit = [_unitList unitAtIndex:unitIndex];
				Sprite * sprite = [[DATManager sharedManager] spriteForUnitIdentifier:[unit type]];
				NSRect boundingRect = [self boundingRectangleForUnit:unit sprite:sprite];
				if( NSPointInRect( transformedPoint , boundingRect )) {
					NSPoint pointInSprite = NSMakePoint( transformedPoint.x - boundingRect.origin.x, transformedPoint.y - boundingRect.origin.y );
					if( [sprite hitTest:pointInSprite] ) {
						selectedSomething = YES;
						[unitEditController addUnit: unit ];
					}
				}
			}
			if( !selectedSomething ) { 
				[unitEditController clearSelection];
			}
			break;
		case MAP_MODE_TERRAIN:
			break;
		case MAP_MODE_UNIT:
			[_unitList addUnitAtX:transformedPoint.x Y:[_map height] * 32 - transformedPoint.y type:[newUnitController newUnitType] owner:[newUnitController newUnitOwner]];
			break;
			
	}

	[self setNeedsDisplay:YES];
}

- (NSRect)boundingRectangleForUnit:(Unit*)unit sprite:(Sprite *)sprite {
	NSRect inRect = NSMakeRect( [unit location].x - [sprite horizOffsetForFrame:0] - ([sprite widthForFrame:0] / 2),
							([_map height] * 32) - [unit location].y - ([sprite heightForFrame:0] / 2 ) - [sprite verticalOffsetForFrame:0],
							[sprite boundingWidth],
							[sprite boundingHeight]);
	NSRectScale( &inRect, 1.0 / _scaleFactor );
	return inRect;
}

@end
